package com.rongji.dfish.base;

import java.io.Serializable;
import java.util.List;

/**
 * Pagination 与Page 作用相当，就是当数据量太大的时候分页。
 * Pagination 使用offset/limit 模式，和网络上大多数接口相似。
 *
 * @author DFish team
 */
public class Pagination<E> implements Serializable {

    /**
     * 页数超出的时候，会自动将页数设置为 最大锁允许的 页数。
     */
    public static final String OVERFLOW_AUTO_FIX="auto";
    /**
     * 页数超出的时候，无需处理。会有其他方式——比如前端判断，处理空数据
     */
    public static final String OVERFLOW_IGNORE="ignore";

    private static final long serialVersionUID = 8563611090473067679L;

    private int limit = -1;
    private int offset;
    private Integer size;
//    private boolean autoRowCount = true;
    private Boolean searchCount;
    private String overflow;
    private List<E> content;

    /**
     * 构造函数
     */
    public Pagination() {
    }

    /**
     * 构造函数
     *
     * @param offset 跳过记录数
     */
    public Pagination(int offset) {
        this.offset = offset;
    }

    /**
     * 构造函数
     *
     * @param offset 跳过记录数
     * @param limit 一页最大记录数
     */
    public Pagination(int offset, int limit) {
        this.offset = offset;
        this.limit = limit;
    }

    /**
     * 构造函数
     * @param content 分页数据
     */
    public Pagination(List<E> content) {
        this.content = content;
    }

    /**
     * 构建Pagination
     *
     * @return 对象本身
     */
    public static Pagination of() {
        return new Pagination();
    }

    /**
     * 构建Pagination
     *
     * @param offset 偏移量，结果从第几条开始显示，初始是0条
     * @return 对象本身
     */
    public static Pagination of(int offset) {
        return new Pagination(offset);
    }

    /**
     * 构建Pagination
     *
     * @param offset 偏移量，结果从第几条开始显示，初始是0条
     * @param limit  结果最多显示多少行
     * @return 对象本身
     */
    public static Pagination of(int offset, int limit) {
        return new Pagination(offset, limit);
    }

    /**
     * 构建Pagination
     * @param page 另外一种形式分页对象
     * @return 对象本身
     */
    public static Pagination of(Page page) {
        if (page == null) {
            throw new IllegalArgumentException("page is null");
        }
        Pagination pagination = new Pagination();
        pagination.setLimit(page.getPageSize());
        pagination.setOffset(page.getCurrentPage() * page.getPageSize() - page.getPageSize());
        pagination.setSearchCount(!page.isAutoRowCount()?Boolean.FALSE:null);
        pagination.setSize(page.getRowCount());
        return pagination;
    }

    /**
     * 构建Pagination
     * @param content 分页数据
     * @param <E> 分页数据对象
     * @return 对象本身
     */
    public static <E> Pagination of(List<E> content) {
        return new Pagination(content);
    }

    /**
     * 是否在查询的时候自动统计行数，默认为true
     *
     * @return boolean
     */
    public Boolean getSearchCount() {
        return searchCount;
    }

    /**
     * 是否在查询的时候自动统计行数，默认为true
     *
     * @param searchCount boolean
     * @return 本身，这样可以继续设置其他属性
     */
    public Pagination setSearchCount(Boolean searchCount) {
        this.searchCount = searchCount;
        return this;
    }

    /**
     * 结果最多显示多少行
     *
     * @return Integer
     */
    public int getLimit() {
        return limit;
    }

    /**
     * 结果最多显示多少行 Integer
     *
     * @param limit Integer
     * @return 本身，这样可以继续设置其他属性
     */
    public Pagination setLimit(int limit) {
        this.limit = limit;
        return this;
    }

    /**
     * 偏移量，结果从第几条开始显示，初始是0条
     *
     * @return int
     */
    public int getOffset() {
        return offset;
    }

    /**
     * 偏移量，结果从第几条开始显示，初始是0条
     *
     * @param offset int
     * @return 本身，这样可以继续设置其他属性
     */
    public Pagination setOffset(int offset) {
        this.offset = offset;
        return this;
    }

    /**
     * 如果开启了autoRowCount 统计出来的行数，讲从这里获取
     *
     * @return Integer
     */
    public Integer getSize() {
        return size;
    }

    /**
     * 如果开启了autoRowCount 统计出来的行数，讲从这里获取
     *
     * @param size Integer
     * @return 本身，这样可以继续设置其他属性
     */
    public Pagination setSize(Integer size) {
        this.size = size;
        return this;
    }

    /**
     * 计算结果从第几条开始显示
     *
     * @param size  总记录数
     * @param limit 每页记录数
     * @return int 计算得出跳过多少记录数
     */
    public static int calculateOffset(int size, int limit) {
        int offset = (size - 1) / limit * limit;
        return offset < 0 ? 0 : offset;
    }



    /**
     * 分页对象转化
     *
     * @param page Page 分页信息
     * @return Pagination对象
     */
    @Deprecated
    public static Pagination fromPage(Page page) {
        return of(page);
    }

    /**
     * 分页对象转化
     *
     * @return Page对象
     */
    public Page toPage() {
        Page page = new Page();
        page.setAutoRowCount(!Boolean.FALSE.equals(this.getSearchCount()));
        page.setRowCount(this.getSize() == null ? 0 : this.getSize());
        page.setPageSize(this.getLimit());
        if (this.getLimit() > 0) {
            int offset = this.getOffset();
            page.setCurrentPage(offset / this.getLimit() + 1);
        }
        return page;
    }

    /**
     * 计算总分页数
     * @return int
     */
    public int calculatePageCount() {
        if (this.getLimit() <= 0) {
            throw new UnsupportedOperationException("limit must greater than zero.");
        }
        if (this.getSize() == null) {
            return 0;
        }
        int pageCount = (this.getSize() + this.getLimit() - 1) / this.getLimit();
        return pageCount;
    }

    /**
     * 获取分页数据
     * @return 分页数据
     */
    public List<E> getContent() {
        return content;
    }

    /**
     * 设置分页数据
     * @param content 分页数据
     * @return 本身，这样可以继续设置其他属性
     */
    public Pagination setContent(List<E> content) {
        this.content = content;
        return this;
    }


    /**
     * 是否在页数超出后自动处理
     * @return
     */
    public String getOverflow() {
        return overflow;
    }

    public void setOverflow(String overflow) {
        this.overflow = overflow;
    }
}